#include "../include/FireworkBase.h"

#include <cmath>
#include <iterator>
#include <algorithm>
#include <ranges>

#include <raymath.h>

void FireworkBase::update(const std::chrono::nanoseconds& delt) {
	if (m_state == FireworkState::Flying) {
		float g = 9.8f;
		float delt_seconds = delt.count() * 1e-9;
		float dz = z_speed * delt_seconds + 0.5f * -g * powf(delt_seconds, 2.0f);

		m_pos.z += dz;

		z_speed += -g * delt_seconds;

		if (z_speed < 0) {
			m_state = FireworkState::Blast;
			initFireworkParticles();
			PlaySound(*m_bombBgm);
		}
	}

	if (m_state == FireworkState::Blast) {
		int m_bombBlastCount =
		    std::ranges::count_if(
		        m_fireworkParticles.cbegin(),
		        m_fireworkParticles.cend(),
		[delt](auto & fireworkParticle) {
			fireworkParticle->update(delt);
			return fireworkParticle->isDone();
		});
		if (m_bombBlastCount >= m_fireworkParticles.size()) {
			m_state = FireworkState::Done;
		}
	}

}

void FireworkBase::draw() {
	if (m_state == FireworkState::Flying) {
		DrawCubeV(m_pos, {1, 1, 5}, RED);
	}
	if (m_state == FireworkState::Blast) {
		for (auto fireworkParticle : m_fireworkParticles) {
			fireworkParticle->draw();
		}
	}
}

void FireworkBase::addNewBombs(Vector3 pos, const std::vector<Vector3>& speedList, Color color, uint8_t lengthBomb) {
	std::vector<std::shared_ptr<FireworkParticle>> newGropuParticles{speedList.size()};
	std::uniform_real_distribution<float> dragCoefficientDis(0.5, 0.99);
	float dragCoefficient = dragCoefficientDis(m_gen);
	std::ranges::transform(
	    speedList.begin(),
	    speedList.end(),
	    newGropuParticles.begin(),
	[ = ](const auto & speed) {
		return std::make_shared<FireworkParticle>(pos, speed, dragCoefficient, color, lengthBomb);
	});
	setBombsMovePara(newGropuParticles);
	std::ranges::copy_n(newGropuParticles.begin(), newGropuParticles.size(), std::back_inserter(m_fireworkParticles));
}
void FireworkBase::setBombsMovePara(const std::vector<std::shared_ptr<FireworkParticle>>& newGropuParticles) {
	std::uniform_real_distribution<float> thetaLDis{1.8, 2.5};
	std::uniform_real_distribution<float> ADis{0.8, 1.2};

	float theta = thetaLDis(m_gen);
	float A = ADis(m_gen);

	// y = A*a**2
	// y = A*(1+D*deltT)**x
	// speed = initSpeed * (1+dragCoefficeint*deltT)**n
	// n = log_(1+deltT)(y/A)
	// 根据初始速度计算出速度接近于0所需的时间，设定为正态方程的均值，以实现在烟花粒子近乎静止时，烟花粒子的半径达到最大，亮度最高

	float deltT = 0.001;
	//	float speedRatio = 0.03;
	float speedEnd = 7;
	for (auto fireworkParticle : newGropuParticles) {
		Vector3 speed = fireworkParticle->speed();
		float D = -fireworkParticle->dragCoefficeint();
		float initSpeed = Vector3Length(speed);
		float a = 1 + D * deltT;
		float n = logf(speedEnd / initSpeed) / logf(a);
		float t = n * deltT * 2;
		fireworkParticle->setMovePara(t, theta, A);
	}
}

void FireworkBase::activate() {
	m_state = FireworkState::Flying;
	PlaySound(*m_raiseBgm);
}
